﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.ServiceModel;
using System.Net;
using System.ServiceModel.Description;
using Automaton.ServiceLibrary;
using NLog;

namespace Automaton.Server
{
    public partial class HostService : ServiceBase
    {

        private static Logger logger = LogManager.GetCurrentClassLogger();
 


        private static EventLog eventlog;

        ServiceHost PLCService;
        ServiceHost DataService;
        string HostName;

        IPAddress[] addr;
        
        string PLCBaseAddy;
        string DataBaseAddy;

        const string category = "HostService";
        System.Uri PLCBaseURI;
        System.Uri DataBaseURI;

        public HostService()
        {
            logger.Debug("HostService()");
            try
            {
                InitializeComponent();
                InitEventLogger();
                HostName = Dns.GetHostName();
                addr = Dns.GetHostAddresses(HostName);
                string IPv4Address = string.Empty;

                foreach (IPAddress addy in addr)
                {
                    switch (addy.AddressFamily)
                    {
                        case System.Net.Sockets.AddressFamily.InterNetwork:
                            IPv4Address = addy.ToString();
                            break;
                        default:
                            break;
                    }
                }

                PLCBaseAddy = "http://" + IPv4Address + ":2626/AutomatonServiceLibrary/PLC/";
                DataBaseAddy = "http://" + IPv4Address + ":2626/AutomatonServiceLibrary/AutomatonDataService/";

                PLCBaseURI = new Uri(PLCBaseAddy);
                DataBaseURI = new Uri(DataBaseAddy);
            }
            catch (Exception ex)
            {
                string _Exception = @"***Host Constructor***
                                        HostName: " + HostName + @"
                                        PLCBaseAddy: " + PLCBaseAddy.ToString() + @"
                                        DataBaseAddy: " + DataBaseAddy.ToString() + @"
                                       ***Host Constructor***";
                logger.FatalException(_Exception, ex);
                WriteWindowsLog("Host: " + ex.ToString(), EventLogEntryType.Error);
            }

            logger.Debug("/HostService()");
        }



        static void InitEventLogger()
        {
            logger.Trace("InitEventLogger()");
            logger.Trace(category.ToString());
            eventlog = new EventLog();
            eventlog.Log = "Application";
            eventlog.Source = category;
            logger.Trace("/InitEventLogger()");
        }

        public static void WriteWindowsLog(string Message, EventLogEntryType Type)
        {
            logger.Trace("WriteWindowsLog()");
            logger.Trace(Message.ToString());
            lock (eventlog)
            {
                if (eventlog != null)
                {
                    eventlog.WriteEntry(Message, Type);
                }
                else
                {
                    InitEventLogger();
                    WriteWindowsLog(Message, Type);
                }
            }
            logger.Trace("/WriteWindowsLog()");
        }

        protected override void OnStart(string[] args)
        {
            logger.Trace("OnStart()");
            try
            {
                SetupPLCService();
                SetupDataService();
            }
            catch (Exception ex)
            {
                WriteWindowsLog("Host OnStart: " + ex.ToString(), EventLogEntryType.Error);
                logger.FatalException("", ex);
            }
            logger.Trace("/OnStart()");

        }

        private void SetupPLCService()
        {
            logger.Trace("SetupPLCService()");
            try
            {
                PLCService = new ServiceHost(typeof(PLC), PLCBaseURI);
                WSHttpBinding searchWSbinding = new WSHttpBinding();
                searchWSbinding.CloseTimeout = new TimeSpan(0, 3, 0);
                searchWSbinding.OpenTimeout = new TimeSpan(2, 3, 0);
                searchWSbinding.ReceiveTimeout = new TimeSpan(0, 10, 0);
                searchWSbinding.SendTimeout = new TimeSpan(0, 10, 0);
                searchWSbinding.MaxBufferPoolSize = 999999999;
                searchWSbinding.MaxReceivedMessageSize = 999999999;
                searchWSbinding.MessageEncoding = WSMessageEncoding.Text;
                searchWSbinding.AllowCookies = false;
                searchWSbinding.ReliableSession.Enabled = true;
                searchWSbinding.ReliableSession.InactivityTimeout = new TimeSpan(1, 0, 0, 0);
                searchWSbinding.Security.Mode = SecurityMode.None;
                searchWSbinding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
                searchWSbinding.Security.Message.ClientCredentialType = MessageCredentialType.None;
                searchWSbinding.Security.Message.NegotiateServiceCredential = false;
                searchWSbinding.Security.Message.EstablishSecurityContext = false;

                //XmlDictionaryReaderQuotas readerQuotas = new XmlDictionaryReaderQuotas();
                //readerQuotas.MaxDepth = 999999999;
                //readerQuotas.MaxStringContentLength = 999999999;
                //readerQuotas.MaxArrayLength = 999999999;
                //readerQuotas.MaxBytesPerRead = 999999999;
                //readerQuotas.MaxNameTableCharCount = 999999999;

                //searchWSbinding.ReaderQuotas = readerQuotas;

                PLCService.AddServiceEndpoint(typeof(IPLC), searchWSbinding, PLCBaseAddy);
                ((ServiceBehaviorAttribute)PLCService.Description.Behaviors[typeof(ServiceBehaviorAttribute)]).MaxItemsInObjectGraph = 999999999;
                ((ServiceBehaviorAttribute)PLCService.Description.Behaviors[typeof(ServiceBehaviorAttribute)]).IncludeExceptionDetailInFaults = true;

                ServiceMetadataBehavior metadataBehavior;
                metadataBehavior =
                   PLCService.Description.Behaviors. 
                   Find<ServiceMetadataBehavior>();
                if (metadataBehavior == null)
                {
                    metadataBehavior = new ServiceMetadataBehavior();
                    metadataBehavior.HttpGetEnabled = true;
                    PLCService.Description.Behaviors.Add(metadataBehavior);
                }
                PLCService.AddServiceEndpoint(
                   typeof(IMetadataExchange), searchWSbinding, "MEX");



                PLCService.Open();
            }
            catch (Exception ex)
            {
                WriteWindowsLog("Host SetupPLCService: " + ex.ToString(), EventLogEntryType.Error);
            }
            logger.Trace("/SetupPLCService()");
        }

        private void SetupDataService()
        {
            logger.Trace("SetupDataService()");
            try
            {
                DataService = new ServiceHost(typeof(Automaton.ServiceLibrary.IAutomatonDataService), DataBaseURI);
                WSHttpBinding WSbinding = new WSHttpBinding();
                WSbinding.CloseTimeout = new TimeSpan(0, 3, 0);
                WSbinding.OpenTimeout = new TimeSpan(0, 3, 0);
                WSbinding.ReceiveTimeout = new TimeSpan(0, 10, 0);
                WSbinding.SendTimeout = new TimeSpan(0, 10, 0);
                WSbinding.MaxBufferPoolSize = 999999999;
                WSbinding.MaxReceivedMessageSize = 999999999;
                WSbinding.MessageEncoding = WSMessageEncoding.Text;
                WSbinding.AllowCookies = false;
                WSbinding.ReliableSession.Enabled = true;
                WSbinding.ReliableSession.InactivityTimeout = new TimeSpan(1, 0, 0, 0);
                WSbinding.Security.Mode = SecurityMode.None;
                WSbinding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
                WSbinding.Security.Message.ClientCredentialType = MessageCredentialType.None;
                WSbinding.Security.Message.NegotiateServiceCredential = false;
                WSbinding.Security.Message.EstablishSecurityContext = false;

                //XmlDictionaryReaderQuotas readerQuotas = new XmlDictionaryReaderQuotas();
                //readerQuotas.MaxDepth = 999999999;
                //readerQuotas.MaxStringContentLength = 999999999;
                //readerQuotas.MaxArrayLength = 999999999;
                //readerQuotas.MaxBytesPerRead = 999999999;
                //readerQuotas.MaxNameTableCharCount = 999999999;

                //indexWSbinding.ReaderQuotas = readerQuotas;

                DataService.AddServiceEndpoint(typeof(IAutomatonDataService), WSbinding, DataBaseAddy);
                ((ServiceBehaviorAttribute)DataService.Description.Behaviors[typeof(ServiceBehaviorAttribute)]).MaxItemsInObjectGraph = 999999999;
                ((ServiceBehaviorAttribute)DataService.Description.Behaviors[typeof(ServiceBehaviorAttribute)]).IncludeExceptionDetailInFaults = true;


                ServiceMetadataBehavior metadataBehavior;
                metadataBehavior =
                   DataService.Description.Behaviors.
                   Find<ServiceMetadataBehavior>();
                if (metadataBehavior == null)
                {
                    metadataBehavior = new ServiceMetadataBehavior();
                    metadataBehavior.HttpGetEnabled = true;
                    DataService.Description.Behaviors.Add(metadataBehavior);
                }
                DataService.AddServiceEndpoint(
                   typeof(IMetadataExchange), WSbinding, "MEX");

                DataService.Open();
            }
            catch (Exception ex)
            {
                WriteWindowsLog("Host SetupDataService: " + ex.ToString(), EventLogEntryType.Error);
            }
            logger.Trace("/SetupDataService()");
        }

       


        protected override void OnStop()
        {
            logger.Trace("OnStop()");
            try
            {
                PLCService.Close();
                PLCService = null;
            }
            catch (Exception ex)
            {
                WriteWindowsLog("Host OnStop: " + ex.ToString(), EventLogEntryType.Error);
            }
            try
            {
                DataService.Close();
                DataService = null;
            }
            catch (Exception ex)
            {
                WriteWindowsLog("Host OnStop: " + ex.ToString(), EventLogEntryType.Error);
            }
            logger.Trace("/OnStop()");
        }


    }
}
